#include <stdio.h>
#include <thread>
#include <chrono>

#include "RrConfig.h"

#include "TimerMngr.h"
#include "RtpComm_I.h"
#include "VideoNetOptimizationSender.h"
#include "VideoNetOptimizationReceiver.h"
#include "Utility.h"
#include "SDLRender.h"
#include "IVideoCodec.h"
#include "IVideoCapture.h"
#include "src/Algorithm/video_net_opti/VideoNetOptimization2/video_net_opti/src/LogeD.h"

#pragma comment(lib, "SDL2.lib")

#undef main

static uint64_t preTime = 0;
static IRtpComm* pIComm = NULL;

static std::mutex m_mutex_sender;

#define CodecType264 0
#define CodecType265 1
#define UseCodecType CodecType264
#define nReceiveNumMax 16

//#define StartStop

static VideoNetOptimizationSender* pVideoNetOptimizationSender[nReceiveNumMax] = {0};
static VideoNetOptimizationReceiver* pVideoNetOptimizationReceiver[nReceiveNumMax] = {0};

static std::map<int, int> g_mapLocalMediaSSrc;
static std::map<int, int> g_mapLocalRtxSSrc;
int nSenderNum = 1;
int nReceiveNum = 1;

bool m_bRuningReceive[nReceiveNumMax] = {false};

bool m_bRuningSender[nReceiveNumMax] = { false };


static int g_senderFrameNum = 0;
static int g_receiveFrameNum = 0;
static int restartCountSender = 0;
static int restartCountReceive = 0;

SDLVRender* pSDLRenderLocal[nReceiveNumMax] = {0};  // 本地显示句柄
SDLVRender* pSDLRenderRemote[nReceiveNumMax] = {0}; // 远端显示句柄
IVideoDecodec* g_pIVideoDecodec[nReceiveNumMax] = {0};  // 视频解码句柄

IVideoEncodec* g_pIVideoEncodec = NULL;  // 视频编码句柄
int g_width = 1280; // 相机采集宽
int g_height = 720; // 相机采集高


int g_send_receive_mode = 0; //0:发送接收   1：发送   2 接收

class VideoNetSenderCallback :public VideoNetOptimizationSenderCallback
{
public:

	VideoNetSenderCallback() {}
	~VideoNetSenderCallback() {}
	// 需要发送RTP包, 交给外边发送(已组成RTP包, 直接按UDP包发送即可)
	virtual void OnRTPToSend(unsigned char* pPacket, int iPacketLen)
	{

		pIComm->SendRtpToNetwork(pPacket, iPacketLen);

	}
	virtual void OnRTCPToSend(unsigned char* pPacket, int iPacketLen)
	{

		uint64_t currentTime = Utility::GetTimestampMs();

		//printf("currentTime = %lld ....use = %lld \n", currentTime, currentTime - preTime);
		preTime = currentTime;

		pIComm->SendRtcpToNetwork(pPacket, iPacketLen);
	}

	virtual void OnBitrateChanged(uint32_t uNewBitrate, uint32_t uRefFrameRate, uint32_t uResolutionIdx, uint8_t uFrLost)
	{
		g_pIVideoEncodec->ChangeBitrate(uNewBitrate);
	}
	virtual void OnRequestKeyFrame()
	{

	}
};

VideoNetSenderCallback* pVideoNetSenderCallback = NULL;


class  VideoNetOptReceiverCallback: public VideoNetOptimizationReceiverCallback
{
public:
	VideoNetOptReceiverCallback()
	{
		static int g_index = 0;
		m_index = g_index;
		g_index++;
	}
    // 回调一个完成一帧数据
    virtual void OnVideoFrame(void* uUserData, const unsigned char* pFrame, uint32_t uFrameLen, const VideoFrameInfo* pFrameInfo, const VNO_RTPFragmentationHeader* pFragmentation)
    {


#if 0
{
        //printf("OnVideoFrame ............ \n");
        uint8_t* p = (uint8_t*)pFrame;
        static FILE* fp = NULL;
        if (fp == NULL)
        {
            fp = fopen("videoNetReceive.h264", "wb");
        }

        if (fp)
        {
            fwrite(pFrame, 1, uFrameLen, fp);
        }
}
#endif


		//unsigned char* pFramebuf = (unsigned char*)pFrame;
		//printf("PlayChanRTP::OnVideoFrame 00 00 00 %x %x %x ,eFrameType:%d, uFrameLen:%d, bComplete:%d, bContinue:%d, uRtpTimestamp:%u  size:%d \n", pFramebuf[3], pFramebuf[4], pFramebuf[5], pFrameInfo->eFrameType, uFrameLen, pFrameInfo->bComplete, pFrameInfo->bContinue, pFrameInfo->uRtpTimestamp, pFragmentation->fragmentationVectorSize);

		if (g_pIVideoDecodec[m_index] == NULL)
		{

			g_pIVideoDecodec[m_index] = IVideoDecodec::CreateVideoDecodec(0);
			int32_t ret = -1;
			if (UseCodecType == CodecType265)
			{
				ret = g_pIVideoDecodec[m_index]->OpenDecodec(265);
			}
			else if (UseCodecType == CodecType264)
			{
				ret = g_pIVideoDecodec[m_index]->OpenDecodec(264);
			}
			if (ret != 0)
			{
				printf("error g_pIVideoDecodec[%d]\n", m_index);
				exit(-1);
			}
		}


		int8_t* yuvData = NULL;
		int width = 0;
		int height = 0;
		if (g_pIVideoDecodec[m_index])
		{
			int32_t ret = g_pIVideoDecodec[m_index]->IncomingEncodeData((int8_t*)pFrame, uFrameLen, yuvData, width, height);

			if (ret == 0)
			{

				if (pSDLRenderRemote[m_index] == NULL)
				{
					pSDLRenderRemote[m_index] = SDLRenderMngr::GetInstance()->CreateSDLVRender();
				}

				if (pSDLRenderRemote[m_index])
				{
					pSDLRenderRemote[m_index]->IncomingYUV((char*)yuvData, width, height);
				}
			}
		}
		
    }

	// added by gc 20210622 调用接口，发送RTCP包
	virtual void OnRTCPToSend(void* uUserData, const unsigned char* pPacket, int iPacketLen)
	{
		if (pIComm)
		{
			pIComm->SendRtcpToNetwork(pPacket, iPacketLen);
		}
	}

	int m_index;
};


// 摄像机采集回调
static int g_count = 0;
class VideoCallBack : public VideoCaptureCallBack
{
public:
	virtual void OnReceiveYuv420(int8_t* data, int32_t width, int32_t hegiht, int64_t timestamp)
	{
		for (int i = 0; i < nSenderNum; i++)
		{
			if (pSDLRenderLocal[i] == NULL)
			{
				pSDLRenderLocal[i] = SDLRenderMngr::GetInstance()->CreateSDLVRender();
			}
		}
		for (int i = 0; i < nSenderNum; i++)
		{

			if (pSDLRenderLocal[i])
			{
				pSDLRenderLocal[i]->IncomingYUV((char*)data, width, hegiht);


				uint8_t* tdata[3];
				int32_t length[3];

			}
		}

		int8_t* p = NULL;
		int len = 0;

		int32_t keyFrame = 0;
        int ret = -1;
		if (g_pIVideoEncodec == NULL)
		{
            g_pIVideoEncodec = IVideoEncodec::CreateVideoEncodec(EncoderFFmpeg); // EncoderOpenH264 EncoderFFmpeg

			if (UseCodecType == CodecType265)
			{
				g_pIVideoEncodec->OpenEncodec(265, width, hegiht, 4096);
			}
			else if (UseCodecType == CodecType264)
			{
				g_pIVideoEncodec->OpenEncodec(264, width, hegiht, 4096);
			}
		}
		if (g_pIVideoEncodec)
		{
			
			ret = g_pIVideoEncodec->IncomingYuv(data, width, hegiht, p, len, keyFrame);
		
		}

		for (int i = 0; i < nSenderNum; i++)
		{
			if (pVideoNetOptimizationSender[i] == NULL)
			{
				pVideoNetOptimizationSender[i] = VideoNetOptimizationSender::pCreateVideoNetOptimizationSender();
			}
		}

		if (ret == 0) // 编码成功
		{

			if (pVideoNetSenderCallback == NULL)
			{
				pVideoNetSenderCallback = new VideoNetSenderCallback();
			}


			int m_RtxpayloadType = SingletonConfig::get_instance().ReadInt(0, "audio", "m_RtxpayloadType", 110);
			int m_PaylaodType = SingletonConfig::get_instance().ReadInt(0, "audio", "m_PaylaodType", 109);


			int m_local_media_ssrc = SingletonConfig::get_instance().ReadInt(0, "audio", "m_local_media_ssrc", 10000);
			int m_remote_media_ssrc = SingletonConfig::get_instance().ReadInt(0, "audio", "m_remote_media_ssrc", 20000);
			int m_rtx_media_ssrc = SingletonConfig::get_instance().ReadInt(0, "audio", "m_rtx_media_ssrc", 30000);
			int VNOProtectionMethod = SingletonConfig::get_instance().ReadInt(0, "audio", "VNOProtectionMethod", 6);
			int VNOEstimateMethod = SingletonConfig::get_instance().ReadInt(0, "audio", "VNOEstimateMethod", 2);

			for (int i = 0; i < nSenderNum; i++)
			{
				if (pVideoNetOptimizationSender[i])
				{

					VideoNetOptimizationSenderParameter oParameter;
					oParameter.m_local_media_ssrc[0] = 0; // m_local_media_ssrc + i;
					oParameter.m_remote_media_ssrc = 0; // m_remote_media_ssrc + i;
					oParameter.m_rtx_media_ssrc[0] = 0; // m_rtx_media_ssrc + i;
					oParameter.m_PayloadType[0] = m_PaylaodType;
					oParameter.m_RtxpayloadType[0] = m_RtxpayloadType;

					oParameter.m_red_payload_type = 96;
					oParameter.m_ulpfec_payload_type = 97;

					oParameter.pCallback = pVideoNetSenderCallback;
					if (UseCodecType == CodecType265)
					{
						oParameter.peCodecType[0] = VNO_CODEC_H265;
					}
					else if (UseCodecType == CodecType264)
					{
						oParameter.peCodecType[0] = VNO_CODEC_H264;
					}
					//pVideoNetOptimizationSender[i] = VideoNetOptimizationSender::pCreateVideoNetOptimizationSender(oParameter);
					oParameter.m_eRemoteBitrateEstimateMethod = (VnoRemoteBitrateEstimateMethod)VNOEstimateMethod;
					oParameter.m_eProtectionMethod = (VideoNetOptimizationProtectionMethod)VNOProtectionMethod;
					oParameter.m_uStartBitrate = 2048;
					oParameter.m_uLowestBitratePercentage = 40;
					oParameter.m_uResolutionNum = 2;

					if (!m_bRuningSender[i])
					
					{
						pVideoNetOptimizationSender[i]->Start(oParameter);
						m_bRuningSender[i] = true;
						restartCountSender++;
						//LOGEM(mTrace, "$$$  pCreateVideoNetOptimizationSender[%d] restartCountSender=%d ...\n",i, restartCountSender);
						pVideoNetOptimizationSender[i]->SetCNAME("Sender_side");

						//pVideoNetOptimizationSender[i]->SetSsrc(10000);
					}
				}

			}
			

			for (int i = 0; i < nSenderNum; i++)
			{
				if (pVideoNetOptimizationSender[i] && len > 0 && m_bRuningSender[i])
				{
					// 增加高精度时间戳
					static uint64_t u64ts = 0;
					static LARGE_INTEGER lastTime;

					LARGE_INTEGER currTime;
					LARGE_INTEGER freq;

					QueryPerformanceCounter(&currTime);
					QueryPerformanceFrequency(&freq);
					uint64_t us = (currTime.QuadPart - lastTime.QuadPart) * 1000000 / freq.QuadPart;

					lastTime = currTime;
					u64ts += us * 90 / 1000;
					// warning!!! 20210809，需要修改对应参数
					pVideoNetOptimizationSender[i]->IncomingVideoFrame(VideoNetOptimizationFrameType(keyFrame), u64ts, (unsigned char*)p, len, nullptr);
					//LOGEM(mTrace, "@@@@[%d]  kyeFrame=%d...\n",i, keyFrame);
				}

			}

			g_senderFrameNum++;

			if (g_senderFrameNum >= 100)
			{
				g_senderFrameNum = 0;
				{
					std::lock_guard<std::mutex> lk(m_mutex_sender);
					for (int i = 0; i < nSenderNum; i++)
					{

						//VideoNetOptimizationSender::vDestroyVideoNetOptimizationSender(pVideoNetOptimizationSender[i]);
						//pVideoNetOptimizationSender[i] = NULL;
						//pVideoNetOptimizationSender[i]->Stop();
						//m_bRuningSender = false; 

#ifdef StartStop
						if (m_bRuningSender[i])
						{
							pVideoNetOptimizationSender[i]->Stop();
							m_bRuningSender[i] = false;
							LOGEM(mTrace, "$$$  pCreateVideoNetOptimizationSender[%d] stop...\n", i);
						}
#endif
						printf("vDestroyVideoNetOptimizationSender ok .. \n");
					}
				}
				
			}


		}
#if 0
		char name[200];
		sprintf(name, "h264/%d.bin", g_count);
		FILE* fp = fopen(name, "wb");
		if (fp)
		{
			fwrite(p, len, 1, fp);
			fclose(fp);
		}

		g_count++;
#endif

		//printf("VideoCallBack ... widht:%d height:%d \n", width, hegiht);

	}
};



VideoNetOptReceiverCallback* pVideoNetOptReceiverCallback[nReceiveNumMax] = {0};

class RtcCommCallBack:IRtpCommCallback
{
public:
	RtcCommCallBack() { }
	virtual ~RtcCommCallBack() { }

public:
	virtual void OnReceivedRtpPacket(uint8_t* packetBuffer, uint32_t packetSize)
	{
       
		//if ((g_send_receive_mode == 2) || (g_send_receive_mode == 0))//接收端创建Receiver
		if(nReceiveNum > 0)
		{
			int m_RtxpayloadType = SingletonConfig::get_instance().ReadInt(0, "audio", "m_RtxpayloadType", 110);
			int m_PaylaodType = SingletonConfig::get_instance().ReadInt(0, "audio", "m_PaylaodType", 109);
			int m_local_ssrc = SingletonConfig::get_instance().ReadInt(0, "audio", "m_local_ssrc", 20000);
			int m_remote_ssrc = SingletonConfig::get_instance().ReadInt(0, "audio", "m_remote_ssrc", 10000);
			int m_rtx_ssrc = SingletonConfig::get_instance().ReadInt(0, "audio", "m_rtx_ssrc", 30000);
			int VNOProtectionMethod = SingletonConfig::get_instance().ReadInt(0, "audio", "VNOProtectionMethod", 6);
			int VNOEstimateMethod = SingletonConfig::get_instance().ReadInt(0, "audio", "VNOEstimateMethod", 2);

			for (int i = 0; i < nReceiveNum; i++)
			{
				if (pVideoNetOptimizationReceiver[i] == NULL)
				{
					pVideoNetOptimizationReceiver[i] = VideoNetOptimizationReceiver::pCreateVideoNetOptimizationReceiver();
				}
				
			}
			// add by zl 20210722 多路测试
			for (int i = 0; i < nReceiveNum; i++)
			{

				if (pVideoNetOptReceiverCallback[i] == NULL)
				{
					pVideoNetOptReceiverCallback[i] = new VideoNetOptReceiverCallback();
				}


				if (pVideoNetOptimizationReceiver[i] != NULL)
				{

					VideoNetOptimizationReceiverParameter oParameter;
					oParameter.m_RtxpayloadType = m_RtxpayloadType;
					oParameter.m_PayloadType = m_PaylaodType;
					oParameter.m_local_ssrc = 0; // m_local_ssrc + i;
					oParameter.m_remote_ssrc = 0; // m_remote_ssrc + i;
					oParameter.m_rtx_ssrc = 0; // m_rtx_ssrc + i;

					oParameter.m_red_payload_type = 96;
					oParameter.m_ulpfec_payload_type = 97;
					oParameter.m_bEnableFrameBuffer = true;

					oParameter.pCallback = pVideoNetOptReceiverCallback[i];
					if (UseCodecType == CodecType265)
					{
						oParameter.eCodecType = VNO_CODEC_H265;
					}
					else if (UseCodecType == CodecType264)
					{
						oParameter.eCodecType = VNO_CODEC_H264;
					}
				

					oParameter.m_eRemoteBitrateEstimateMethod = (VnoRemoteBitrateEstimateMethod)VNOEstimateMethod;
					oParameter.m_eProtectionMethod = (VideoNetOptimizationProtectionMethod)VNOProtectionMethod;
					
					if (!m_bRuningReceive[i])
					{
						pVideoNetOptimizationReceiver[i]->Start(oParameter);
						
						m_bRuningReceive[i] = true;
						restartCountReceive++;

						//LOGEM(mTrace, " pCreateVideoNetOptimizationReceiver[%d] restartCountReceive=%d .. \n", i, restartCountReceive);

						LOGEM(mTrace, "hello world ... \n");

					}
					

						
				}
			}

			
		}





		for (int i = 0; i < nReceiveNum; i++)
		{
			bool ret = 0;
			if (pVideoNetOptimizationReceiver[i] && m_bRuningReceive[i])
			{
				pVideoNetOptimizationReceiver[i]->IncomingRtpPacket(packetBuffer, packetSize, ret);
			}

		} 

		g_receiveFrameNum++;

		if (g_receiveFrameNum >= 600)
		{
			g_receiveFrameNum = 0;

			std::lock_guard<std::mutex> lk(m_mutex_sender);
			for (int i = 0; i < nReceiveNum; i++)
			{

				if (pVideoNetOptimizationReceiver[i])
				{
					//VideoNetOptimizationReceiver::vDestroyVideoNetOptimizationReceiver(pVideoNetOptimizationReceiver[i]);
					//pVideoNetOptimizationReceiver[i] = NULL;
					//pVideoNetOptimizationReceiver[i]->Stop();
					//m_bRuningReceive = false;
#ifdef StartStop
					if (m_bRuningReceive[i])
					{
						pVideoNetOptimizationReceiver[i]->Stop();
						m_bRuningReceive[i] = false;
						LOGEM(mTrace, "###  pVideoNetOptimizationReceiver[%d] stop...\n", i);
					}
#endif
				}

			}
		}



		//printf("OnReceivedRtpPacket packetSize:%d .. \n", packetSize);
	}
	virtual void OnReceivedRtcpPacket(uint8_t* packetBuffer, uint32_t packetSize)
	{
		// added by gc 20210628 将所有的rtcp的数据发送给vno send, vno recv, SR RR包由网络适应性模块处理

		// add by zl 20210722 多路时候，分发给每一路
		{
			std::lock_guard<std::mutex> lk(m_mutex_sender);
			for (int i = 0; i < nSenderNum; i++)
			{

				if (m_bRuningSender[i])
				{
					pVideoNetOptimizationSender[i]->IncomingRTCPPacket(packetBuffer, packetSize);
				}

			}

		}
		

		for (int i = 0; i < nReceiveNum; i++)
		{
			if (pVideoNetOptimizationReceiver[i])
			{
				if (m_bRuningReceive[i])
				{
					pVideoNetOptimizationReceiver[i]->IncomingRtcpPacket(packetBuffer, packetSize);
				}
				
			}
		}

	}
};






int main()
{


	int8_t buffer[1200];

	printf("buffer:%p %p \n", buffer, buffer + 1);

	VNOInitParam mVNOInitParam;
	mVNOInitParam.ulRcvrWorkThreadNum = 2;
	//int ret = iVNO_Init(&mVNOInitParam);
	printf("111111111111 \n");

	//bool isOk = SingletonConfig::get_instance().Init();

	nSenderNum = SingletonConfig::get_instance().ReadInt(0, "audio", "nSenderNum", 1);
	nReceiveNum = SingletonConfig::get_instance().ReadInt(0, "audio", "nReceiveNum", 1);;

	LOGEM(mTrace,"nSenderNum=%d nReceiveNum=%d \n", nSenderNum, nReceiveNum);

	uint32_t num = 2;
	//if ((g_send_receive_mode == 1) || (g_send_receive_mode == 2))
	if(1 == (nSenderNum + nReceiveNum))
	{
		num = 1;
	}

	int maxSR = nSenderNum > nReceiveNum ? nSenderNum : nReceiveNum;
	if (maxSR > 1 && maxSR <= 4)
	{
		num = 2;
	}
	else if ((maxSR > 4 && maxSR <= 9))
	{
		num = 3;
	}
	else if ((maxSR > 9 && maxSR <= 16) )
	{
		num = 4;
	}

    SDLRenderMngr::GetInstance()->InitializeV(num);
/*
	if (pSDLRenderLocal == NULL)
	{
        pSDLRenderLocal = SDLRenderMngr::GetInstance()->CreateSDLVRender();
	}
*/
	std::string sRemote_ip = SingletonConfig::get_instance().ReadString(0, "audio", "remote_ip", "127.0.0.1");

	TimerMngr::GetInstance(IndexNetThread)->Initialize(1);

	IRtpCommCallback* rtpCommCallback = (IRtpCommCallback *)new RtcCommCallBack();
	
    if (pIComm == NULL)
    {
        pIComm = IRtpComm::CreateRtpComm(rtpCommCallback);

        pIComm->StartWork((const int8_t*)sRemote_ip.c_str(), 48004, 48005, 48004, 48005);
    }



//if ((g_send_receive_mode == 1) || (g_send_receive_mode == 0)) //发送端创建本地采集
{
	if (nSenderNum > 0)
	{
		VideoCallBack* pVideoCallBack = new VideoCallBack();

		IVideoCapture* pIVideoCapture = IVideoCapture::CreateVideoCapture(pVideoCallBack);

		pIVideoCapture->Connect((int32_t)0, (int32_t)g_width, (int32_t)g_height, (int32_t)30);

	}


}

	static int g_test = 0;

	while (true)
	{
	
		std::this_thread::sleep_for(std::chrono::seconds(4));
		g_test++;

		//VideoReceiverStatistics * p = pVideoNetOptimizationReceiver[0]->GetStatistics();

		if (pVideoNetOptimizationReceiver[0])
		{
			int32_t tPassRateRemote = 0;
			int32_t tPassRateLocal = 0;
			int32_t tDownstreamBandwidth = 0;
			pVideoNetOptimizationReceiver[0]->GetNetworkStatus(tPassRateRemote, tPassRateLocal, tDownstreamBandwidth);

			
			printf("########## ************* remote:%d local:%d tDownstreamBandwidth:%d \n", tPassRateRemote, tPassRateLocal, tDownstreamBandwidth);

			VideoReceiverStatistics * pVideoReceiverStatistics = pVideoNetOptimizationReceiver[0]->GetStatistics();
			printf("########## ************* uFractionLost:%d uRtt:%d uFractionOutOfOrder:%d  \n", pVideoReceiverStatistics->uFractionLost, pVideoReceiverStatistics->uRtt, pVideoReceiverStatistics->uFractionOutOfOrder);
			
		}


		//if (g_test == 15)
		{
			for (int i = 0; i < nSenderNum; i++)
			{
				if (pVideoNetOptimizationSender[i])
				{
					//pVideoNetOptimizationSender[i]->SetMute(true);

					int32_t tUpstreamBandwidth = 0;
					pVideoNetOptimizationSender[i]->GetNetworkStatus(tUpstreamBandwidth);

					printf("########## ************* local  tUpstreamBandwidth:%d \n",  tUpstreamBandwidth);
				}
			}
		}

	}


	return 0;
}